package com.rinoiot.weather.utils;

import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.GeoOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@AllArgsConstructor
public class GeoUtil {

    private RedisTemplate redisTemplate;

    /**
     * 向指定key中添加经纬度信息
     *
     * @param key       存储的键值
     * @param longitude 经度
     * @param latitude  纬度
     * @param member    成员名称(数据的标识 比如userID)
     * @return 添加成功的条数
     */
    public long geoAdd(String key, Double longitude, Double latitude, String member) {
        return redisTemplate.opsForGeo().add(key, new Point(longitude, latitude), member);
    }

    /**
     * 向指定key中添加经纬度信息
     *
     * @param key
     * @param locations
     * @return
     */
    public long geoAddList(String key, List<RedisGeoCommands.GeoLocation<String>> locations) {
        return redisTemplate.opsForGeo().add(key, locations);
    }

    /**
     * 获取成员之间的距离
     *
     * @param key     存储的键值
     * @param member1 成员名称
     * @param member2 成员名称
     * @return
     */
    public Distance geoDist(String key, String member1, String member2) {
        return redisTemplate.opsForGeo().distance(key, member1, member2);
    }

    /**
     * 获取指定key值的所有成员列表
     *
     * @param key
     * @return
     */
    public List<String> geoHash(String key) {
        return redisTemplate.opsForGeo().hash(key);
    }

    /**
     * 获取指定key值的所有成员列表
     *
     * @param key
     * @return
     */
    public List<String> geoHashList(String key, String[] serviceStations) {
        GeoOperations<String, String> ops = redisTemplate.opsForGeo();
        return ops.hash(key, serviceStations);
    }

    /**
     * 获取指定成员的位置信息
     *
     * @param key    存储的键值
     * @param member 成员名称
     * @return
     */
    public Point geoPos(String key, String member) {
        return (Point) (redisTemplate.opsForGeo().position(key, member)).get(0);
    }

    /**
     * 获取指定成员 范围内的位置信息
     *
     * @param key      存储的键值
     * @param member   成员名称
     * @param distance 距离
     * @return
     */
    public GeoResults<RedisGeoCommands.GeoLocation<String>> geoRadius(String key, String member, double distance) {
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates()
                .sortAscending();
        return redisTemplate.opsForGeo().radius(key, member, new Distance(distance, Metrics.KILOMETERS), args);
    }


    /**
     * 根据给定地理位置坐标获取指定范围内的地理位置集合
     *
     * @param key      存储的键值
     * @param lng      经度
     * @param lat      纬度
     * @param distance 距离（公里）
     * @return {@link RedisGeoCommands.GeoLocation}
     */
    public GeoResults<RedisGeoCommands.GeoLocation<String>> getPointRadius(String key, Double lng, Double lat, int distance) {
        Circle within = new Circle(new Point(lng, lat), new Distance(distance, Metrics.KILOMETERS));
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
                .includeDistance() //包含距离
                .includeCoordinates() //包含经纬度
                .sortAscending()//正序排序
                .limit(50); //条数
        return redisTemplate.opsForGeo().radius(key, within, args);
    }


    /**
     * 批量删除
     *
     * @param key  存储的键值
     * @param name 成员名称
     * @return
     */
    public Long deleteBatchRedisGeo(String key, String[] name) {
        return redisTemplate.boundZSetOps(key).remove(name);
    }

    /**
     * 单个删除
     *
     * @param key  存储的键值
     * @param name 成员名称
     * @return
     */
    public Long deleteRedisGeo(String key, String name) {
        return redisTemplate.boundZSetOps(key).remove(name);
    }

}
